package com.itlong.cloud.operate.service.impl;

import com.itlong.cloud.POJO.DTO.operate.OperateAppPackageGetPageDTO;
import com.itlong.cloud.POJO.PO.AppPackagePO;
import com.itlong.cloud.POJO.PO.PropertyRoleFunctionPO;
import com.itlong.cloud.POJO.VO.operate.OperateAppPackageGetPageVO;
import com.itlong.cloud.PlatformConstants;
import com.itlong.cloud.constants.RedisConstant;
import com.itlong.cloud.enumerate.DataStatusEnum;
import com.itlong.cloud.enumerate.PropertyPublicRoleEnum;
import com.itlong.cloud.operate.dao.IOperateAppFunctionInfoDao;
import com.itlong.cloud.operate.dao.IOperateAppPackageDao;
import com.itlong.cloud.operate.dao.IOperatePropertyPackageDao;
import com.itlong.cloud.operate.service.IOperateAppPackageService;
import com.itlong.cloud.service.RedisService;
import com.itlong.cloud.thrown.DataAccessException;
import com.itlong.cloud.utils.data.handler.SqlUtil;
import com.itlong.cloud.utils.page.Page;
import com.itlong.cloud.utils.random.LogicIdUtil;
import com.itlong.cloud.utils.words.StringHandlerUtil;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * <desc>
 *      运营-APP管理-套餐管理业务处理接口实现类
 * </desc>
 *
 * @createDate 2017/11/01
 */
@Service
public class OperateAppPackageServiceImpl implements IOperateAppPackageService{
    @Autowired
    IOperateAppPackageDao iOperateAppPackageDao;

    @Autowired
    IOperateAppFunctionInfoDao iOperateAppFunctionInfoDao;

    @Autowired
    IOperatePropertyPackageDao iOperatePropertyPackageDao;

    ExecutorService cachedThreadPool = Executors.newFixedThreadPool(5);

    @Autowired
    RedisService redisService;
    /**
     * <desc>
     *      保存套餐
     * </desc>
     *
     * @param appPackagePO 套餐实体
     * @return sql执行行数
     * @author Jiaqi.X
     * @createDate 2017/11/01
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public String save(AppPackagePO appPackagePO) throws Exception{
        appPackagePO.setAppPackageId(LogicIdUtil.bussinessId());
        appPackagePO.setStatus(DataStatusEnum.NORMAL.getType());
        appPackagePO.setCreateTime(new Date());
        iOperateAppPackageDao.save(SqlUtil.durableData(appPackagePO, PlatformConstants.TABLE_SAVE));
        //保存默认菜单
        List<String> functions = iOperateAppFunctionInfoDao.getDefaultFunctions();
        List<String> miniFunctions = iOperateAppFunctionInfoDao.getMiniDefaultFunctions();
        //保存app默认菜单
        iOperateAppFunctionInfoDao.allotFunction(
                functions.toArray(new String[functions.size()]),
                appPackagePO.getAppPackageId(),1, DataStatusEnum.NORMAL.getType(), new Date());
        //保存小程序默认菜单
        iOperateAppFunctionInfoDao.allotFunction(
                miniFunctions.toArray(new String[miniFunctions.size()]),
                appPackagePO.getAppPackageId(),2, DataStatusEnum.NORMAL.getType(), new Date());
        return appPackagePO.getAppPackageId();

    }

    /**
     * <desc>
     *      更新套餐
     * </desc>
     *
     * @param appPackagePO 套餐实体
     * @return sql执行行数
     * @author Jiaqi.X
     * @createDate 2017/11/01
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer update(AppPackagePO appPackagePO) throws Exception{
        appPackagePO.setUpdateTime(new Date());
        return iOperateAppPackageDao.update(SqlUtil.durableData(appPackagePO,PlatformConstants.TABLE_UPDATE));
    }


    /**
     * <desc>
     *      通过id获取功能
     * </desc>
     *
     * @param appPackagePO 套餐实体
     * @return 套餐实体
     * @author Jiaqi.X
     * @createDate 2017/11/01
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public AppPackagePO getOne(AppPackagePO appPackagePO){
        return iOperateAppPackageDao.getOne(appPackagePO);
    }

    /**
     * <desc>
     *      获取所有套餐
     * </desc>
     *
     * @return 套餐实体集合
     * @author Jiaqi.X
     * @createDate 2017/11/01
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<AppPackagePO> getList(){
        return iOperateAppPackageDao.getList();
    }

    /**
     * <desc>
     *      获取分页数据
     * </desc>
     *
     * @param pageDTO 查询参数DTO
     * @return page模型
     * @author Jiaqi.X
     * @createDate 2017/11/01
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Page<OperateAppPackageGetPageVO> getPage(OperateAppPackageGetPageDTO pageDTO) throws Exception{
        if (StringUtils.isBlank(pageDTO.getOrderColumn()) || StringUtils.isBlank(pageDTO.getOrderRule())){
            pageDTO.setOrderColumn("createDate");
            pageDTO.setOrderRule("DESC");
        }
        //将DTO转换为Map params
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(pageDTO);
        //分页类默认pageSize为20
        Page<OperateAppPackageGetPageVO> page = new Page<>();
        page.getPage().setPageSize(pageDTO.getPageSize());
        page.getPage().setCurrentPage(pageDTO.getCurrentPage());
        params.put("currentPage", page.getPage().getStartSlip());
        params.put("pageSize", page.getPage().getPageSize());
        //填充返回数据集
        page.setRows(iOperateAppPackageDao.getPage(params), iOperateAppPackageDao.getPageCount(params));
        return page;
    }

    /**
     * <desc>
     *      删除功能
     * </desc>
     *
     * @param appPackageIds 套餐id数组
     * @return sql执行行数
     * @author Jiaqi.X
     * @createDate 2017/09/21
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer delete(String appPackageIds){
        String[] ids = StringHandlerUtil.splitString(appPackageIds);
        //删除套餐关联的项目
        iOperateAppPackageDao.deleteProjectByPackages(ids);
        //删除套餐绑定的功能
        iOperateAppPackageDao.deleteFunctionByPackages(ids);
        return iOperateAppPackageDao.delete(ids,new Date());
    }

    /**
     * <desc>
     *      套餐分配功能
     * </desc>
     *
     * @param appFunctionIds 功能id 多个,号分隔
     * @param appPackageId  套餐id
     * @return
     * @author Jiaqi.X
     * @createDate 2017/11/01
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer allotFunction(String appFunctionIds, String appPackageId,Integer systemType) {

        //获取旧的功能列表
        List<String> functionList = iOperatePropertyPackageDao.getFunctionIds(appPackageId);
        //删除套餐功能
        iOperateAppPackageDao.deletePackageFunctions(appPackageId,systemType);
        String[] appFunctionId=StringHandlerUtil.splitString(appFunctionIds);
        if(appFunctionId.length>0) {
            iOperateAppFunctionInfoDao.allotFunction(
                    StringHandlerUtil.splitString(appFunctionIds),
                    appPackageId,systemType, DataStatusEnum.NORMAL.getType(), new Date());
        }
        Map<String, Object> params = new HashMap<>();
        params.put("appPackageId",appPackageId);
        params.put("updateTime",new Date());
        iOperateAppPackageDao.updateOperateTime(params);

        //当系统类型为3（物业菜单）需处理关联物业账号的菜单权限
        if (3 == systemType){
            this.handlePropertyFunction(appFunctionIds, appPackageId, functionList);
        }
        return 1;
    }

    public static void main(String[] args) {

    }

    /**
     * <desc>
     *      套餐分配项目
     * </desc>
     *
     * @param appPackageId 套餐id
     * @param allotProjectIds 待分配的项目id
     * @param projectIds 当前页所有项目id
     * @return
     * @author Jiaqi.X
     * @createDate 2017/11/02
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public Integer allotPackageProject(String appPackageId, String allotProjectIds, String projectIds) throws Exception{

        //找出分配前套餐绑定的项目
        List<String> oldProjectId = iOperateAppPackageDao.getAppPackageProjectIds(StringHandlerUtil.splitString(appPackageId));
        //当前套餐在当前页的项目
        List<String> currentOldProjectId  = new ArrayList<>();
        //筛选出没有勾选的项目id
        List<String> noProjectId = new ArrayList<>(Arrays.asList(StringHandlerUtil.splitString(projectIds)));
        String[] allotProjectId=StringHandlerUtil.splitString(allotProjectIds);
        for(int i = noProjectId.size() -1 ; i >= 0 ; i--){
            for(String projectId : allotProjectId){
                if(projectId.equals(noProjectId.get(i))){
                    noProjectId.remove(i);
                    break;
                }
            }
        }
        //遍历没有勾选的项目id 如果存在套餐名相同，且存在于数据库中，表示这是被取消的项目，做删除处理
        noProjectId.forEach(projectId->{
            iOperateAppPackageDao.deleteCancelAllotProject(appPackageId,projectId);
        });
        oldProjectId.forEach(item ->{
            if (projectIds.contains(item)){
                currentOldProjectId.add(item);
            }
        });

        currentOldProjectId.removeAll(Arrays.asList(allotProjectId));
        //删除被取消的项目下账号的菜单
        if (!currentOldProjectId.isEmpty()){
            iOperateAppPackageDao.deleteUserFunctions(currentOldProjectId);
        }
        //删除套餐关联的项目
        if(!allotProjectIds.isEmpty()) {
            iOperateAppPackageDao.deletePackageProject(appPackageId, StringHandlerUtil.splitString(allotProjectIds));
        }

        //删除被取消的菜单权限
        for (String projectId : allotProjectId){
            List<String> functionList = iOperatePropertyPackageDao.getFunctionIds(appPackageId);
            List<String> functionListCopy = new ArrayList<>(functionList);
            List<String> oldFunctionIds = iOperateAppFunctionInfoDao.getFunctionByProjectId(projectId);
            List<String> oldFunctionIdsCopy = new ArrayList<>(oldFunctionIds);
            oldFunctionIdsCopy.removeAll(functionList);
            //删除项目下所有用户应该被取消的菜单权限
            if (!oldFunctionIdsCopy.isEmpty()){
                Map<String, Object> deleteParams= new HashMap<>();
                deleteParams.put("projectId", projectId);
                deleteParams.put("functionIds", oldFunctionIdsCopy);
                iOperateAppFunctionInfoDao.deleteUserFunctions(deleteParams);
            }
            //添加新权限
            functionListCopy.removeAll(oldFunctionIds);
            if (!functionListCopy.isEmpty()){
                List<PropertyRoleFunctionPO> roleFunctionPOList = new ArrayList<>();
                Date nowTime = new Date();
                for (String functionId : functionListCopy){
                    PropertyRoleFunctionPO roleFunctionPO = new PropertyRoleFunctionPO();
                    roleFunctionPO.setFunctionId(functionId);
                    roleFunctionPO.setProjectId(projectId);
                    roleFunctionPO.setRoleId(PropertyPublicRoleEnum.ADMIN.getRoleId());
                    roleFunctionPO.setStatus(DataStatusEnum.NORMAL.getType());
                    roleFunctionPO.setCreateTime(nowTime);
                    roleFunctionPOList.add(roleFunctionPO);
                    //添加集团物业管理员账号菜单
                    PropertyRoleFunctionPO groupRoleFunctionPO = new PropertyRoleFunctionPO();
                    groupRoleFunctionPO.setFunctionId(functionId);
                    groupRoleFunctionPO.setProjectId(projectId);
                    groupRoleFunctionPO.setRoleId(PropertyPublicRoleEnum.GROUP_ADMIN.getRoleId());
                    groupRoleFunctionPO.setCreateTime(nowTime);
                    groupRoleFunctionPO.setStatus(DataStatusEnum.NORMAL.getType());
                    roleFunctionPOList.add(groupRoleFunctionPO);
                }
                iOperateAppFunctionInfoDao.batchSaveRoleFunction(roleFunctionPOList);
            }
        }

        //删除要分配该套餐的项目之前关联的套餐,并重新保存
        if(allotProjectId.length>0) {
            iOperateAppPackageDao.deleteProjectOldPackages(allotProjectId);
            iOperateAppPackageDao.allotPackageProject(appPackageId,
                    StringHandlerUtil.splitString(allotProjectIds),
                    DataStatusEnum.NORMAL.getType(), new Date());
        }
        Map<String, Object> params = new HashMap<>();
        params.put("appPackageId",appPackageId);
        params.put("updateTime",new Date());
        iOperateAppPackageDao.updateOperateTime(params);
        return 1;
    }

    /**
     * <desc>
     *      获取当前套餐已有的项目id集合
     * </desc>
     *
     * @param appPackageId 套餐id
     * @return
     * @author Jiaqi.X
     * @createDate 2017/11/02
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<String> getAppPackageProjectIds(String appPackageId) {
        return iOperateAppPackageDao.getAppPackageProjectIds(StringHandlerUtil.splitString(appPackageId));
    }

    /**
     * <desc>
     *      获取已绑定套餐的项目id
     * </desc>
     *
     * @param appPackageId app套餐id
     * @return
     * @Author Zhu.yj
     * @createDate  2020/4/3
     */
    @Override
    public List<String> getOtherProjectIds(String appPackageId) throws Exception {
        return iOperateAppPackageDao.getOtherProjectIds(appPackageId);
    }

    /**
     * <desc>
     *      根据套餐id获取场景列表
     * </desc>
     *
     * @param appPackageId 套餐
     * @return
     * @Author Zhu.yj
     * @createDate  2021/4/8
     */
    @Override
    public List<String> getSceneIdByPackageId(String appPackageId) throws Exception {
        return iOperateAppPackageDao.getSceneIdByPackageId(appPackageId);
    }

    /**
     * <desc>
     *      校验项目是否绑定套餐
     * </desc>
     *
     * @param
     * @return
     * @Author Zhu.yj
     * @createDate  2021/5/19
     */
    @Override
    public List<Map<String, Object>> checkProjectsIsBindPackage(List<String> projectIdList) throws Exception {
        return iOperateAppPackageDao.checkProjectsIsBindPackage(projectIdList);
    }

    /**
     * <desc>
     *      删除套餐后处理受影响项目的功能菜单
     * </desc>
     *
     * @param propertyFunctionIds 套餐内的菜单id列表
     * @param propertyPackageId 套餐id
     * @param functionList 当前页所有菜单
     * @return
     * @Author Zhu.yj
     * @createDate  2021/3/29
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void handlePropertyFunction(String propertyFunctionIds, String propertyPackageId, List<String> functionList){
        cachedThreadPool.execute(()->{
            try{
                redisService.set(RedisConstant.PROPERTY_PACKAGE_HANDLER_PROPERTY_FUNCION_KEY + propertyPackageId, "flag");
                List<String> functionListCopy = new ArrayList<>(functionList);
                Date nowTime = new Date();
                List<String> propertyFunctionIdList = StringHandlerUtil.splitStringList(propertyFunctionIds);
                List<String> propertyFunctionIdListCopy = new ArrayList<>(propertyFunctionIdList);
                //找出该套餐绑定的项目，变更该项目下物业账号的菜单权限
                List<Map<String, Object>> projectList = iOperatePropertyPackageDao.getPropertyPackageAccount(propertyPackageId);
                if (!projectList.isEmpty()){
//                    //删除套餐绑定项目下的物业管理员账号与集团物业管理员的菜单权限
//                    iOperatePropertyPackageDao.removeRoleProjectFunction(projectList);

                    //要删除的菜单权限
                    functionList.removeAll(propertyFunctionIdList);
                    //找出要添加的菜单权限
                    propertyFunctionIdListCopy.removeAll(functionListCopy);
                    //重新分配
                    List<PropertyRoleFunctionPO> propertyRoleFunctionPOS = new ArrayList<>();
                    List<PropertyRoleFunctionPO> propertyRoleFunctionPODeleteList = new ArrayList<>();
                    for (Map<String, Object> projectIdMap : projectList){

                        for (String functionId : propertyFunctionIdListCopy){
                            //要添加的
                            PropertyRoleFunctionPO propertyRoleFunctionPO = new PropertyRoleFunctionPO();
                            propertyRoleFunctionPO.setRoleId(projectIdMap.get("roleId").toString());
                            propertyRoleFunctionPO.setProjectId(projectIdMap.get("projectId").toString());
                            propertyRoleFunctionPO.setCreateTime(nowTime);
                            propertyRoleFunctionPO.setUpdateTime(nowTime);
                            propertyRoleFunctionPO.setFunctionId(functionId);
                            propertyRoleFunctionPOS.add(propertyRoleFunctionPO);
                        }
                        //要删除的
                        for (String functionId : functionList){
                            PropertyRoleFunctionPO propertyRoleFunctionPODelete = new PropertyRoleFunctionPO();
                            propertyRoleFunctionPODelete.setProjectId(projectIdMap.get("projectId").toString());
                            propertyRoleFunctionPODelete.setFunctionId(functionId);
                            propertyRoleFunctionPODeleteList.add(propertyRoleFunctionPODelete);
                        }
                    }
                    if (!propertyRoleFunctionPOS.isEmpty()){
                        iOperatePropertyPackageDao.saveRoleProjectFunction(propertyRoleFunctionPOS);
                    }

                    if (!propertyRoleFunctionPODeleteList.isEmpty() && StringUtils.isNotBlank(propertyRoleFunctionPODeleteList.get(0).getFunctionId())){
                        iOperatePropertyPackageDao.removeOtherPropertyFunction(propertyRoleFunctionPODeleteList);
                    }
                }
            }catch (Exception e){
                throw new DataAccessException("分配物业菜单异常", e);
            }finally {
                redisService.del(RedisConstant.PROPERTY_PACKAGE_HANDLER_PROPERTY_FUNCION_KEY + propertyPackageId);
            }
        });
    }


}
